using Game.Networking.Server;
using System.Collections.Generic;
using UnityEngine;
using Utils;

namespace Game {
	public class ShipCargo {
		const float EnergyPerCraftedRocket = 2000;

		public float GrabRadius = 6f;
		BaseInventory _inventory;
		ShipCore      _owner;

		Collider[] _tmpColliderArray = new Collider[32];

		public EventBus OnCargoCollected = new EventBus();

		public BaseInventory Inventory => _inventory;

		public ShipCargo(ShipCore owner) {
			_inventory = new BaseInventory(16);
			_owner = owner;
		}

		public List<CargoContainer> GetNearbyGrabbableItems() {
			var count = Physics.OverlapSphereNonAlloc(_owner.transform.position, GrabRadius, _tmpColliderArray, CommonStaticData.Instance.DynamicEntitiesMask);
			var result = new List<CargoContainer>(count);
			for ( int i = 0; i < count; i++ ) {
				var cargo = _tmpColliderArray[i].GetComponent<CargoContainer>();
				if ( !cargo ) {
					continue;
				}
				result.Add(cargo);
			}
			return result;
		}

		public int TryCollectAll() {
			var nearbyItems = GetNearbyGrabbableItems();
			if ( nearbyItems.Count == 0 ) {
				return 0;
			}
			var collectedContainersCount = 0;
			for ( int i = 0; i < nearbyItems.Count; i++ ) {
				if ( nearbyItems[i].Collect(_inventory, _owner.ID) ) {
					collectedContainersCount++;
				}
			}
			if ( collectedContainersCount > 0 ) {
				OnCargoCollected.Fire();
			}
			return collectedContainersCount;
		}

		public bool TryCollectItem(EntitySummary target) {
			if ( target == null || target.Type != EntityType.CargoContainer ) {
				return false;
			}
			return TryCollectItem(target.ID);
		}

		public bool TryCollectItem(uint objectId) {
			var e = ServerEntityController.Instance.GetEntityById(objectId);
			if ( e == null || e.EntityType != EntityType.CargoContainer ) {
				return false;
			}
			var cont = (CargoContainer)e;
			if ( cont == null || Vector3.Distance(_owner.transform.position, cont.transform.position) > GrabRadius ) {
				return false;
			}
			if ( cont.Collect(_inventory, _owner.ID) ) {
				OnCargoCollected.Fire();
				return true;
			}
			return false;
		}

		public bool TryAddItem(BaseInventoryItem item) {
			if ( item == null ) {
				return false;
			}
			return _inventory.AddItem(item, true);
		}

		public void TryDropAll() {
			var items = _inventory.Items;
			for ( int i = 0; i < items.Count; i++ ) {
				TryDropFromSlot(i);
			}
		}

		public void CreateDebris() {
			var count = Random.Range(2, 5);
			var ownerTr = _owner.transform;
			for ( int i = 0; i < count; i++ ) {
				var item = new DebrisItem() {
					Count = 1
				};
				var container = CargoContainer.SpawnFromPayload(ownerTr.position + Random.onUnitSphere * 0.5f, Random.rotation.eulerAngles, new List<BaseInventoryItem> { item });
				container.CreatorID = _owner.ID;
				if ( container.Rb) {
					container.Rb.AddExplosionForce(1f, ownerTr.position, 2f);
				}
			}			
		}

		public void TryDropFromSlot(int slotIndex, int count = int.MaxValue) {
			var item = _inventory.DropItemsFromSlot(slotIndex, count);
			if ( item == null ) {
				return;
			}
			var ownerTr = _owner.transform;
			var sphereDeviation = Random.insideUnitSphere;
			sphereDeviation.y = Mathf.Abs(sphereDeviation.y);
			sphereDeviation += Vector3.up * 0.5f;

			var container = CargoContainer.SpawnFromPayload(ownerTr.position + ownerTr.TransformDirection(-sphereDeviation), Random.rotation.eulerAngles, new List<BaseInventoryItem> { item });
			container.CreatorID = _owner.ID;
		}

		public InventoryItemDescription GetInventorySlotInfo(int slotIndex) {
			var item = _inventory.GetItemInSlot(slotIndex);
			if ( item == null ) {
				return new InventoryItemDescription() {
					Name = "None",
					Count = 0,
					Type = InventoryItemType.Unknown
				};
			}
			return new InventoryItemDescription() {
				Type = item.ItemType,
				Count = item.Count,
				Name = item.ItemName
			};
		}

		public List<InventoryItemDescription> GetInventorySlotsInfo() {
			var result = new List<InventoryItemDescription>();
			for ( int i = 0; i < _inventory.Items.Count; i++ ) {
				result.Add(GetInventorySlotInfo(i));
			}
			return result;
		}

		public bool CraftMissile() {
			if ( !_owner.Reactor.HasEnergy(EnergyPerCraftedRocket) ) {
				return false;
			}
			if ( !_inventory.ConsumeItem(new BlockItem() { BlockData = new Voxels.BlockData(Voxels.BlockType.IronBlock, 0, 255, 0, 0, 0), Count = 2, ItemType = InventoryItemType.Block }, 2) ) {
				return false;
			}
			_owner.Reactor.UseEnergy(EnergyPerCraftedRocket);
			var rocket = new AmmoItem() { AmmoType = AmmoType.Missile, Count = 1, ItemType = InventoryItemType.Ammo };
			return _inventory.AddItem(rocket, true);
		}
	}
}
